package com.example.uploadfile.controller;

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import jakarta.servlet.http.HttpServletRequest;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 文件上传下载接口
 */
@RestController
@RequestMapping("/file")
public class FileController {

    @Value("${upload.dir:uploads}")
    private String uploadDir;

    private static final Logger logger = LoggerFactory.getLogger(FileController.class);

    /**
     * 上传文件接口
     * <p>
     * 接收前端上传的文件，保存到指定目录，并返回可直接访问的下载URL（包含协议、IP、端口、项目名等）。
     * </p>
     * @param file 前端上传的文件（表单字段名为file）
     * @param request HttpServletRequest对象，用于获取请求的协议、IP、端口、项目名等信息
     * @return 可直接访问的下载URL（如：http://127.0.0.1:8080/项目名/file/download/xxx.txt）
     * @throws IOException 文件名非法或保存文件失败时抛出
     */
    @PostMapping("/upload")
    public Map<String, String> upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
        String filename = StringUtils.cleanPath(file.getOriginalFilename()).trim();
        logger.info("收到上传请求，文件名: {}", filename);
        // 禁止非法文件名，防止windows路径异常
        if (filename.isEmpty() || filename.contains("..") || filename.contains("/") || filename.contains("\\") || filename.contains(":") || filename.contains("<") || filename.contains(">") || filename.contains("|") || filename.contains("\"") || filename.contains("?")) {
            throw new IOException("非法文件名: " + filename);
        }
        File dir = new File(uploadDir);
        if (!dir.exists()) dir.mkdirs();
        Path path = Paths.get(uploadDir, filename);
        file.transferTo(path);

        // 只返回相对路径
        String url = String.format("/file/download/%s", filename);
        Map<String, String> result = new HashMap<>();
        result.put("url", url);
        return result;
    }

    /**
     * 下载文件接口
     * <p>
     * 根据文件名从指定目录读取文件并以附件形式下载，若文件不存在或文件名非法则返回相应错误。
     * </p>
     * @param filename 要下载的文件名（路径参数）
     * @return 文件资源的ResponseEntity，包含下载所需的响应头和文件内容
     * @throws IOException 文件读取异常
     */
    @GetMapping("/download/{filename}")
    public ResponseEntity<Resource> download(@PathVariable String filename) throws IOException {
        filename = filename.trim();
        logger.info("收到下载请求，文件名: {}", filename);
        // 同样校验文件名
        if (filename.isEmpty() || filename.contains("..") || filename.contains("/") || filename.contains("\\") || filename.contains(":") || filename.contains("<") || filename.contains(">") || filename.contains("|") || filename.contains("\"") || filename.contains("?")) {
            return ResponseEntity.badRequest().build();
        }
        Path filePath = Paths.get(uploadDir, filename);
        if (!Files.exists(filePath)) {
            return ResponseEntity.notFound().build();
        }
        Resource resource = new FileSystemResource(filePath);
        String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8);
        ResponseEntity<Resource> response = ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encodedFilename)
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(resource);


        return response;
    }

    /**
     * 健康检查接口，测试服务是否可用
     */
    @GetMapping("/health")
    public Map<String, String> health() {
        logger.info("健康检查接口被调用");
        Map<String, String> result = new HashMap<>();
        result.put("status", "ok");
        return result;
    }

    /**
     * 保存字符串内容为UUID文件名接口
     * <p>
     * 接收JSON对象（如{"content":"内容"}），将content字段内容保存为UUID文件名的txt文件，并返回可访问的下载URL。
     * </p>
     * @param jsonObj JSON对象，需包含content字段，表示要保存的字符串内容
     * @param request HttpServletRequest对象，用于获取请求的协议、IP、端口、项目名等信息
     * @return 可直接访问的下载URL（如：http://127.0.0.1:8080/项目名/file/download/xxxx.txt）
     * @throws IOException 文件保存失败时抛出
     */
    @PostMapping("/saveJSON")
    public Map<String, String> saveStringToFile(@RequestBody JSONObject jsonObj, HttpServletRequest request) throws IOException {
        String filename = UUID.randomUUID().toString() + ".txt";
        logger.info("收到保存字符串内容请求，生成文件名: {}", filename);
        File dir = new File(uploadDir);
        if (!dir.exists()) dir.mkdirs();
        Path path = Paths.get(uploadDir, filename);
        Files.write(path, jsonObj.getString("content").getBytes(StandardCharsets.UTF_8));
        // 只返回相对路径
        String url = String.format("/file/download/%s", filename);
        Map<String, String> result = new HashMap<>();
        result.put("url", url);
        return result;
    }
} 
